package org.whuims.core.dataprocessor.page;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.NlpAnalysis;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by Qikai.
 */
public class SentStructureBuilder {
    Set<String> proSet = new HashSet<String>();
    Set<String> omitTerms = new HashSet<String>();
    private List<String> lines;
    private String filePath;
    private List<String> quotas = new ArrayList<String>();

    public SentStructureBuilder(List<String> lines) {
        this.lines = lines;
        addFilters();
    }

    public SentStructureBuilder(String filePath) {
        this.filePath = filePath;
        try {
            lines = FileUtils.readLines(new File(this.filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        addFilters();
    }

    public static void main(String[] args) {
        String filePath = "src/main/webapp/resource/txt/CN-GB/GB_T 13754-2008_374.txt";//GB/T 13754—2008
        SentStructureBuilder builder = new SentStructureBuilder(filePath);
        builder.build();
    }

    public List<String> getQuotas() {
        return quotas;
    }

    private void addFilters() {
        proSet.add("度");
        proSet.add("量");
//        proSet.add("性");
        proSet.add("差");
        proSet.add("率");
        proSet.add("值");
        proSet.add("耗");
        omitTerms.add("规范性");
        omitTerms.add("定性");
        omitTerms.add("定量");
        omitTerms.add("正规性");
        omitTerms.add("效率");
        omitTerms.add("分值");
        omitTerms.add("总值");
        omitTerms.add("制度");
        omitTerms.add("质量");
        omitTerms.add("数值");
        omitTerms.add("能量");
        omitTerms.add("规定");
        omitTerms.add("平均值");
    }

    public String build() {
        return firstAnalyze();
    }

    /**
     * 找出篇头、主体和篇尾
     */
    private String firstAnalyze() {
        List<String> headSents = new ArrayList<String>();
        //List<String> indexSents = new ArrayList<String>();
        List<String> mainSents = new ArrayList<String>();
        List<String> bottomSents = new ArrayList<String>();

        List<List<String>> pages = new ArrayList<List<String>>();
        List<PageUnit> pageUnits = buildPages(pages);
        //识别各个page的类型
        PageTypeDetector detector = new PageTypeDetector(pageUnits);
        detector.detect();

        List<List<String>> result = reconstructPage(pageUnits);
        buildHeadSents(headSents, pageUnits.get(0), result.get(0));
        buildMainPartSents(mainSents, result.get(1));
        mainSents = annonate(mainSents);
        buildBottomSents(bottomSents, result.get(2));
        bottomSents = annonate(bottomSents);
        return concate(headSents, mainSents, bottomSents);
    }

    private List<String> annonate(List<String> sents) {
        List<String> result = new ArrayList<String>();
        for (int i = 0; i < sents.size(); i++) {
            String sent = sents.get(i);
            sent = sent.replace("<p>", "").replace("</p>", "");
            sent = segAndAnnonae(sent);
            sent = "<p>" + sent + "</p>";
            result.add(sent);
        }
        return result;
    }

    /**
     * 指标的简单标注，不是非常可信的结果，先用着吧。
     *
     * @param sent
     * @param quotas
     * @return
     */
    private String segAndAnnonae(String sent) {
        List<Term> terms = NlpAnalysis.parse(sent).getTerms();
        Set<String> matchedTerms = new HashSet<String>();
        for (int i = 0; i < terms.size(); i++) {
            Term term = terms.get(i);
            String termStr = term.getName();
            String nature = term.getNatureStr();
            if (nature.startsWith("n") && probable(termStr)) {
                matchedTerms.add(termStr);
            } else if (termStr.equals("大于") || termStr.equals("等于") || termStr.equals("小于")) {
                for (int j = i; j > -1; j--) {
                    if (terms.get(j).getNatureStr().startsWith("n") && !omitTerms.contains(terms.get(j).getName())) {
                        matchedTerms.add(terms.get(j).getName());
                        break;
                    }
                }
            }
        }
        this.quotas.addAll(matchedTerms);
        for (String str : matchedTerms) {
            sent = sent.replace(str, "<quota>" + str + "</quota>");
        }
        return sent;
    }

    private boolean probable(String term) {
        for (String str : proSet) {
            if (term.endsWith(str) && !omitTerms.contains(str)) {
                return true;
            }
        }
        return false;
    }

    private String concate(List<String> headSents, List<String> mainSents, List<String> bottomSents) {
        StringBuffer sb = new StringBuffer();
        sb.append(StringUtils.join(headSents, "\r\n"));
        sb.append("\r\n<MainPartBegin>\r\n");
        sb.append(StringUtils.join(mainSents, "\r\n"));
        sb.append("\r\n<MainPartEnd>\r\n");
        sb.append(StringUtils.join(bottomSents, "\r\n"));
        return sb.toString().trim();
    }

    private void buildMainPartSents(List<String> mainSents, List<String> strList) {
        StringBuffer sb = new StringBuffer();
        boolean lastLineStartsWithDigit = false;
        for (int i = 0; i < strList.size(); i++) {
            String line = strList.get(i);
            String trimLine = line.trim();
            //如果是Mainpart的开头，直接在前面添加一个换行符。
            if (line.contains("围") || line.contains("总")) {
                //System.out.println("当前文本："+line);
                if (line.trim().replaceAll("\\s+", "").equals("1范围") || line.replaceAll("\\s+", "").startsWith("1适用范围") || line.matches("\\s*1\\s*总\\s*则") || line.equals("1主题内容与适用范围") || line.matches("[第1一章编总则范围主题]+")) {
                    sb.append("\n");
                }
            }
            //上一行为数字开头的，且这一行以空格开头，该行前换行
            if (lastLineStartsWithDigit && line.startsWith(" ")) {
                sb.append("\n");
            }
            //以数字开头的，直接在前面换行。
            if (line.matches("\\d+.+?")) {
                sb.append("\n");
                lastLineStartsWithDigit = true;
            } else {
                lastLineStartsWithDigit = false;
            }
            boolean isThisLineTableHead = false;
            if (trimLine.replaceAll("\\s+", "").matches("[表图]\\d+.+?")) {
                sb.append("\n");
                isThisLineTableHead = true;
            }
            sb.append(line);
            //如果这一行是表标题，直接换行
            if (isThisLineTableHead) {
                sb.append("\n");
            }
            if (trimLine.endsWith(":") || trimLine.endsWith("：")) {
                sb.append("\n");
            }
        }
        String sbStr = sb.toString().trim();
        List<String> array = InnerSplit(sb.toString().trim());
        for (String str : array) {
            if (str.trim().equals("")) {
                continue;
            }
            StringBuffer tsb = new StringBuffer();
            tsb.append("<p>");
            tsb.append(str.replace("\n", "").replace("\r", ""));
            tsb.append("</p>");
            mainSents.add(tsb.toString());
        }
    }

    private void buildBottomSents(List<String> bottomSents, List<String> strList) {
        for (String line : strList) {
            StringBuffer sb = new StringBuffer();
            sb.append("<p>");
            sb.append(line);
            sb.append("</p>");
            bottomSents.add(sb.toString());
        }
    }

    /**
     * 头部文本处理成一个个的句子
     *
     * @param headSents
     * @param firstPage
     * @param strList
     */
    private void buildHeadSents(List<String> headSents, PageUnit firstPage, List<String> strList) {
        //第一页的内容无需任何处理，一行一句，直接处理
        for (String line : firstPage.getLines()) {
            StringBuffer sb = new StringBuffer();
            sb.append("<p>");
            sb.append(line);
            sb.append("</p>");
            headSents.add(sb.toString());
        }
        boolean findDot = false;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < strList.size(); i++) {
            String line = strList.get(i);
            //System.out.println("正在处理："+line);
            if (line.contains("。")) {
                findDot = true;
            }
            //如果前面空格特别多，说明靠右的字符
            if (line.startsWith("     ")) {
                sb.append("\n");
            }
            sb.append(line);
            if (!findDot && line.endsWith("公告")) {
                sb.append("\n");
            }
            if (line.endsWith(":") || line.endsWith("：")) {
                sb.append("\n");
            }
            String l = line.replaceAll("\\s+", "");

            if (l.equals("前言")) {
                sb.append("\n");
            }
        }
        String sbStr = sb.toString().trim();
        List<String> array = InnerSplit(sb.toString().trim());
        for (String str : array) {
            if (str.trim().equals("")) {
                continue;
            }
            StringBuffer tsb = new StringBuffer();
            tsb.append("<p>");
            tsb.append(str.replace("\n", "").replace("\r", ""));
            tsb.append("</p>");
            headSents.add(tsb.toString());
        }
    }

    private List<String> InnerSplit(String str) {
        List<String> result = new ArrayList<String>();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            sb.append(ch);
            if (ch == '\n' || ch == ';' || ch == '；' || ch == '。') {
                result.add(sb.toString());
                sb = new StringBuffer();
            }
        }
        return result;
    }

    /**
     * 根据page类型和规则重建文本，注意，这里的文本处理没办法很好的处理表格，需要后期人工处理
     *
     * @param pageUnits
     */
    private List<List<String>> reconstructPage(List<PageUnit> pageUnits) {
        List<List<String>> result = new ArrayList<List<String>>();
        List<String> headLines = new ArrayList<String>();
        List<String> mainLines = new ArrayList<String>();
        List<String> bottomLines = new ArrayList<String>();
        for (int i = 1; i < pageUnits.size(); i++) {
            PageUnit pu = pageUnits.get(i);
            if (pu.getType().equals(PageUnit.PAGE_HEAD)) {
                headLines.addAll(pu.getLines());
            } else if (pu.getType().equals(PageUnit.PAGE_MAIN_PART)) {
                mainLines.addAll(pu.getLines());
            } else if (pu.getType().equals(PageUnit.PAGE_COPYRIGHT)) {
                bottomLines.addAll(pu.getLines());
            }
        }
        result.add(headLines);
        result.add(mainLines);
        result.add(bottomLines);
        return result;
    }

    /**
     * 将文本加工成
     *
     * @param pages
     */
    private List<PageUnit> buildPages(List<List<String>> pages) {
        pages.add(new ArrayList<String>());
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
//            System.out.println(line);
            if (line.contains("===============") || line.contains("===========")) {
                pages.add(new ArrayList<String>());
            } else {
                pages.get(pages.size() - 1).add(line);
            }
        }
        removeGBEtc(pages);
        removePageNumber(pages);
        List<PageUnit> units = new ArrayList<PageUnit>();
        int pageNumber = 0;
        for (List<String> page : pages) {
            if (page.size() == 0) {
                continue;
            }
            PageUnit unit = new PageUnit();
            unit.setLines(page);
            unit.setPageNumber(pageNumber);
            pageNumber++;
            units.add(unit);
        }
        return units;
    }

    private void removePageNumber(List<List<String>> pages) {
        double idCount = 0;
        double count = 0;
        for (int i = 1; i < pages.size(); i++) {
            List<String> list = pages.get(i);
            if (list.size() == 0) continue;
            String firstLine = list.get(list.size() - 1).trim();
            if (firstLine.matches("[iIl\\d]+")) {
                idCount++;
            }
            count++;
        }
        boolean toIDRemove = false;
        if (idCount / count > 0.6 && idCount > 2) {
            toIDRemove = true;
        }
        if (toIDRemove) {
            for (int i = 0; i < pages.size(); i++) {
                List<String> list = pages.get(i);
                if (list.size() == 0) continue;
                String firstLine = list.get(list.size() - 1).trim();
                if (firstLine.matches("[iIl\\d]+")) {
                    list.remove(list.size() - 1);
                }
            }
        }
    }

    /**
     * 如果页面第一行是标准编号，删除掉这些编号，下面的代码就是干这个的。
     *
     * @param pages
     */
    private void removeGBEtc(List<List<String>> pages) {
        double gbCount = 0;
        double count = 0;
        for (int i = 1; i < pages.size(); i++) {
            List<String> list = pages.get(i);
            if (list.size() == 0) continue;
            String firstLine = list.get(0).trim();
            if (firstLine.matches("[GBHJDL]+.+?\\d+")) {
                gbCount++;
            }
            count++;
        }
        boolean toGBRemove = false;
        if (gbCount / count > 0.6 && gbCount > 2) {
            toGBRemove = true;
        }
        if (toGBRemove) {
            for (int i = 0; i < pages.size(); i++) {
                List<String> list = pages.get(i);
                if (list.size() == 0) continue;
                String firstLine = list.get(0).trim();
                if (firstLine.matches("[GBHJDL]+.+?\\d+")) {
                    list.remove(0);
                }
            }
        }
    }

}

